#include <cstdlib>
#include <cstring>
#include <iostream>

/*
   一些常见的面试题

   1. 手动修改派生类对象的虚表指针，使两个派生类调用对方的虚函数

   2. 基类和派生类的同名覆盖方法，其参数默认值永远使用的是基类形参默认值
        在编译时生成汇编指令时，函数调用，先把参数压栈，这个过程发生在编译时期，与运行时动态多态无关！
   3.
   函数的访问权限在编译时期确定，而动态多态在运行时确定，所以派生类的同名覆盖方法是私有的，而基类同名覆盖方法是公有的，依然可以通过动态多态调用派生类的虚函数！
 */
#if 0
class Base {
public:
    virtual void show(int a = 10) {
        std::cout << "a=" << a << std::endl;
        std::cout << "Base::show()" << std::endl;
    }
};

class Foo : public Base {
private:
    void show(int a = 20) {
        std::cout << "a=" << a << std::endl;
        std::cout << "Foo::show()" << std::endl;
    }
};

class Bar : public Base {
private:
    void show(int a = 30) {
        std::cout << "a=" << a << std::endl;
        std::cout << "Bar::show()" << std::endl;
    }
};

int main() {
    Base* pb1 = new Foo;
    Base* pb2 = new Bar;

    int* pb11 = (int*)pb1;
    int* pb22 = (int*)pb2;

    // 手动修改虚表指针，使两个派生类调用对方的虚函数
    int tmp = pb11[0];
    pb11[0] = pb22[0];
    pb22[0] = tmp;

    pb1->show();  // Bar::show()
    pb2->show();  // Foo::show()

    delete pb1;
    delete pb2;

    std::cout << "=====================================" << std::endl;
    Foo f;
    Bar b;
    Base& r1 = f;
    Base& r2 = b;
    r1.show();  // 默认参数10压栈 而不是动态多态时压入对应默认参数
    r2.show();  // 默认参数10压栈 而不是动态多态时压入对应默认参数

    std::cout << "=====================================" << std::endl;
    Foo f2;
    /* f2.show();  // 'show' is a private member of 'Foo' */
    Base& r3 = f2;
    r3.show();  // 编译时确定函数访问权限，运行时确定虚函数调用地址
}

#endif

/**
4.
 */

class Base {
public:
    Base() {
        std::cout << "Base()" << std::endl;
        clear();
    }

    void clear() {
        memset(this, 0, sizeof(*this));  // 将虚表指针置为 0x00000000
    }
    virtual void show() {
        std::cout << "Base::show()" << std::endl;
    }
};

class Derived : public Base {
public:
    Derived() {
        std::cout << "Derived()" << std::endl;
    }
    void show() {
        std::cout << "Derived::show()" << std::endl;
    }
};

int main() {
    Base b;
    b.show();

    /* Base* pb = new Base; */
    /* pb->show();  // 多态， 但是虚表指针被破坏，会出现未定义行为 */
    /* delete pb; */

    Base* pd = new Derived;
    pd->show();
    delete pd;
}
